home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / smaltalk / gnu_st.lha / gnu_st / smalltalk-1.1.1 / mstdict.c < prev    next >
C/C++ Source or Header  |  1991-09-12  |  56KB  |  2,201 lines

  1. /***********************************************************************
  2.  *
  3.  *    Dictionary Support Module.
  4.  *
  5.  ***********************************************************************/
  6.  
  7. /***********************************************************************
  8.  *
  9.  * Copyright (C) 1990, 1991 Free Software Foundation, Inc.
  10.  * Written by Steve Byrne.
  11.  *
  12.  * This file is part of GNU Smalltalk.
  13.  *
  14.  * GNU Smalltalk is free software; you can redistribute it and/or modify it
  15.  * under the terms of the GNU General Public License as published by the Free
  16.  * Software Foundation; either version 1, or (at your option) any later 
  17.  * version.
  18.  * 
  19.  * GNU Smalltalk is distributed in the hope that it will be useful, but WITHOUT
  20.  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
  21.  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  22.  * more details.
  23.  * 
  24.  * You should have received a copy of the GNU General Public License along with
  25.  * GNU Smalltalk; see the file COPYING.  If not, write to the Free Software
  26.  * Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  
  27.  *
  28.  ***********************************************************************/
  29.  
  30.  
  31. /*
  32.  *    Change Log
  33.  * ============================================================================
  34.  * Author      Date       Change 
  35.  * sbb         12 Sep 91      Changed to support edit numbers in version string.
  36.  *
  37.  * sbyrne    21 Apr 90      Added toByteArray.
  38.  *
  39.  * sbyrne     7 Jan 90      Added more commentary to classes, added new global
  40.  *              Smalltalk variable: Bigendian, which allows code 
  41.  *              to be conditional based on the architecture type.
  42.  *
  43.  * sbyrne     7 Sep 89      Started adding garbage collection support.
  44.  *
  45.  * sbyrne    29 May 89      Added the memory classes.  Added the FileStream about
  46.  *              a week ago.
  47.  *
  48.  * sbyrne    29 Apr 89      Author changed from single to married.
  49.  *
  50.  * sbyrne     5 Apr 89      Restructured Class and Metaclass creation.  Is now
  51.  *              table driven, and metaclasses are created containing
  52.  *              the proper information.
  53.  *
  54.  * sbyrne    29 Mar 89      Removed MethodDictionary as a separate type; it is an
  55.  *              IdentityDictionary. 
  56.  *
  57.  * sbyrne    11 Mar 89      Smalltalk is now an instance of SystemDictionary.
  58.  *
  59.  * sbyrne    13 Jan 89      Created.
  60.  *
  61.  */
  62.  
  63.  
  64. #include "mst.h"
  65. #include "mstdict.h"
  66. #include "mstoop.h"
  67. #include "mstinterp.h"
  68. #include "mststr.h"
  69. #include "mstsym.h"
  70. #include "mstmain.h"
  71. #include <stdio.h>
  72.  
  73. #define INITIAL_DICTIONARY_SIZE        32 /* chosen at random */
  74.  
  75.  
  76. /***********************************************************************
  77.  *
  78.  *    Below are the structural definitions for several of the important
  79.  *    objects present in the Smalltalk system.  Their C representation
  80.  *    corresponds exactly with their Smalltalk representation.
  81.  *
  82.  ***********************************************************************/
  83.  
  84. typedef struct DictionaryStruct {
  85.   OBJ_HEADER;
  86.   OOP        tally;        /* really, an int */
  87.   OOP        assoc[1];    /* variable sized array of associations */
  88.   /* Other, indexable fields that are the associations for this dictionary */
  89. } *Dictionary;
  90.  
  91. typedef struct IdentityDictionaryStruct {
  92.   OBJ_HEADER;
  93.   OOP        tally;        /* really, an int */
  94.   OOP        values;        /* an Array */
  95.   OOP        keys[1];    /* variable sized array of OOPS (symbols) */
  96. } *IdentityDictionary;
  97.  
  98. typedef struct AssociationStruct {
  99.   OBJ_HEADER;
  100.   OOP        key;
  101.   OOP        value;
  102. } *Association;
  103.  
  104. typedef struct ArrayStruct {
  105.   OBJ_HEADER;
  106.   OOP        elements[1];    /* elements of the array */
  107. } *Array;
  108.  
  109. typedef struct FloatObjectStruct {
  110.   OBJ_HEADER;
  111.   double    value;
  112. } *FloatObject;
  113.  
  114. typedef struct StringStruct {
  115.   OBJ_HEADER;
  116.   char        chars[1];
  117. } *String;
  118.  
  119. typedef struct ByteArrayStruct {
  120.   OBJ_HEADER;
  121.   Byte        bytes[1];
  122. } *ByteArray;
  123.  
  124. typedef struct MessageStruct {
  125.   OBJ_HEADER;
  126.   OOP        selector;
  127.   OOP        args;
  128. } *Message;
  129.  
  130. typedef struct ClassInfoStruct {
  131.   OOP        *classVar;
  132.   OOP        *superClassPtr;
  133.   Boolean    isPointers;
  134.   Boolean    isWords;
  135.   Boolean    isIndexable;
  136.   char        numFixedFields;
  137.   char        *name;
  138.   char        *instVarNames;
  139.   char        *classVarNames;
  140.   char        *sharedPoolNames;
  141.   char        *comment;
  142. } ClassInfo;
  143.  
  144. /* Primary class variables. These variables hold the class objects for
  145.    all of the builtin classes in the system */
  146. OOP            objectClass, magnitudeClass, charClass, timeClass,
  147.             dateClass,
  148.             numberClass, floatClass, integerClass, lookupKeyClass,
  149.             associationClass, linkClass, processClass,
  150.             symLinkClass, collectionClass,
  151.             sequenceableCollectionClass, linkedListClass,
  152.             semaphoreClass,
  153.             arrayedCollectionClass, arrayClass, stringClass,
  154.             symbolClass, byteArrayClass, compiledMethodClass,
  155.             intervalClass, orderedCollectionClass,
  156.             sortedCollectionClass, bagClass, mappedCollectionClass,
  157.             setClass, dictionaryClass, 
  158.             systemDictionaryClass,
  159.             identityDictionaryClass, undefinedObjectClass,
  160.             booleanClass, falseClass, trueClass, 
  161.             processorSchedulerClass, delayClass, sharedQueueClass,
  162.             behaviorClass,
  163.             classDescriptionClass, classClass, metaclassClass,
  164.             smalltalkDictionary, messageClass, methodContextClass,
  165.             blockContextClass, 
  166.             streamClass, positionableStreamClass, readStreamClass,
  167.             writeStreamClass, readWriteStreamClass,
  168.             cObjectClass, fileStreamClass, memoryClass,
  169.             byteMemoryClass, wordMemoryClass, randomClass,
  170.             cFuncDescriptorClass, tokenStreamClass,
  171.             methodInfoClass, fileSegmentClass,
  172.             processorOOP;
  173.  
  174. void             setAssociationValue();
  175.  
  176. static Dictionary    growDictionary();
  177. static IdentityDictionary growIdentityDictionary();
  178. static InstanceSpec    classInstanceSpec();
  179. static OOP        identityDictionaryNew(), systemDictionaryNew(),
  180.             newClass(), newMetaclass();
  181. static void        initSmalltalkDictionary(), addSmalltalk(),
  182.             printOOPClassName(), printClassName(),
  183.             createClassesPass1(), createClassesPass2(),
  184.             addSubClass(), addSTDIOObject();
  185. static int        oopNumFields();
  186.  
  187. /* The class definition structure.  From this structure, the initial set of
  188.    Smalltalk classes are defined.  Note that the comment field is largely
  189.    superfluous, thanks to the comment: primitive and the universal use
  190.    of the class and class comment declarations throughout the Smalltalk
  191.    method definition files.  In any dispute, the comment definition in the
  192.    ".st" file wins. */
  193.  
  194. static ClassInfo classInfo[] = {
  195.   { &objectClass,        nil,
  196.       true,    true,    false,    0,
  197.       "Object",        nil,    nil,    "Smalltalk CFunctionDescs",
  198.       "I am the root of the Smalltalk class system. \n\
  199. All classes in the system are subclasses of me." },
  200.  
  201.   { &magnitudeClass,        &objectClass,
  202.       true,    true,    false,    0,
  203.       "Magnitude",    nil,    nil,    nil,
  204.       nil },
  205.  
  206.   { &messageClass,        &objectClass,
  207.       true,    true,    false,    2,
  208.       "Message",    "selector args",    nil,    nil,
  209.       nil },
  210.  
  211.   { &charClass,            &magnitudeClass,
  212.       false,    true,    true,    0, /* really has 1 indexed var */
  213.       "Character",    nil,    nil,    nil,
  214.       "My instances represent the 256 characters of the character set.  I provide\n\
  215. messages to translate between integers and character objects, and provide \n\
  216. names for some of the common unprintable characters." },
  217.  
  218.   { &timeClass,            &magnitudeClass,
  219.       true,    true,    false,    1,
  220.       "Time",        "seconds",    nil,    nil,
  221.       nil },
  222.  
  223.   { &dateClass,            &magnitudeClass,
  224.       true,    true,    false,    1,
  225.       "Date",        "days",    nil,    nil,
  226.       nil },
  227.  
  228.   { &numberClass,        &magnitudeClass,
  229.       true,    true,    false,    0,
  230.       "Number",        nil,    nil,    nil,
  231.       nil },
  232.  
  233.   { &floatClass,        &numberClass,
  234.       false,    true,    false,    0,    /* really 2, but we're variable sized*/
  235.       "Float",        nil,    nil,    nil,
  236.       nil },
  237.  
  238.   { &integerClass,               &numberClass,
  239.       false,    true,    false,    0,
  240.       "Integer",    nil,    nil,    nil,
  241.       nil },
  242.  
  243.   { &lookupKeyClass,        &magnitudeClass,
  244.       true,    true,    false,    0,
  245.       "LookupKey",    nil,    nil,    nil,
  246.       nil },
  247.  
  248.   { &associationClass,        &lookupKeyClass,
  249.       true,    true,    false,    2,
  250.       "Association",    "key value",    nil,    nil,
  251.       nil },
  252.  
  253.   { &linkClass,            &objectClass,
  254.       true,    true,    false,    1,
  255.       "Link",            "nextLink",    nil,    nil,
  256.       nil },
  257.  
  258.   { &processClass,        &linkClass,
  259.       true,    true,    false,    3,
  260.       "Process",    "suspendedContext priority myList",    nil,    nil,
  261.       nil },
  262.  
  263.   { &symLinkClass,        &linkClass,
  264.       true,    true,    false,    1,
  265.       "SymLink",    "symbol",    nil,    nil,
  266.       nil },
  267.  
  268.   { &collectionClass,        &objectClass,
  269.       true,    true,    false,    0,
  270.       "Collection",    nil,    nil,    nil,
  271.       nil },
  272.  
  273.   { &sequenceableCollectionClass,    &collectionClass,
  274.       true,    true,    true,    0,
  275.       "SequenceableCollection",    nil,    nil,    nil,
  276.       nil },
  277.  
  278.   { &linkedListClass,        &sequenceableCollectionClass,
  279.       true,    true,    false,    2,
  280.       "LinkedList",    "firstLink lastLink",    nil,    nil,
  281.       nil },
  282.  
  283.   { &semaphoreClass,        &linkedListClass,
  284.       true,    true,    false,    1,
  285.       "Semaphore",    "signals",    nil,    nil,
  286.       nil },
  287.  
  288.   { &arrayedCollectionClass,    &sequenceableCollectionClass,
  289.       true,    true,    true,    0,
  290.       "ArrayedCollection",    nil,    nil,    nil,
  291.       nil },
  292.  
  293.   { &arrayClass,        &arrayedCollectionClass,
  294.       true,    true,    true,    0,
  295.       "Array",      nil,    nil,    nil,
  296.       nil },
  297.  
  298.   { &stringClass,        &arrayedCollectionClass,
  299.       false,    false,    true,    0,
  300.       "String",        nil,    nil,    nil,
  301.       nil },
  302.  
  303.   { &symbolClass,        &stringClass,
  304.       false,    false,    true,    0,
  305.       "Symbol",        nil,    nil,    nil,
  306.       nil },
  307.  
  308.   { &byteArrayClass,        &arrayedCollectionClass,
  309.       false,    false,    true,    0,
  310.       "ByteArray",    nil,    nil,    nil,
  311.       nil },
  312.  
  313.   { &compiledMethodClass,    &arrayedCollectionClass,
  314.       false,    false,    true,    2, /* leave this this way */
  315.       "CompiledMethod",    "descriptor methodHeader",    nil,    nil, 
  316.       "I represent methods that have been compiled.  I can recompile \n\
  317. methods from their source code, I can invoke Emacs to edit the source code \n\
  318. for one of my instances, and I know how to access components of my \n\
  319. instances." },
  320.  
  321.   { &intervalClass,    &sequenceableCollectionClass,
  322.       true,    true,    false,    3,
  323.       "Interval",    "start stop step", nil,    nil,
  324.       "My instances represent ranges of objects, typically Magnitude type\n\
  325. objects.  I provide iteration/enumeration messages for producing all the\n\
  326. members that my instance represents." },
  327.  
  328.   { &orderedCollectionClass,    &sequenceableCollectionClass,
  329.       true,    true,    true,    2,
  330.       "OrderedCollection",    "firstIndex lastIndex",    nil,    nil,
  331.       nil },
  332.  
  333.   { &sortedCollectionClass,    &orderedCollectionClass,
  334.       true,    true,    true,    1,
  335.       "SortedCollection",    "sortBlock",    nil,    nil,
  336.       "I am a collection of objects, stored and accessed according to some\n\
  337. sorting criteria.  I store things using a bubble sort.  My instances have a \n\
  338. comparison block associated with them; this block takes two arguments and\n\
  339. is a predicate which returns true if the first argument should be sorted \n\
  340. earlier than the second.  The default block is [ :a :b | a <= b ], but I\n\
  341. will accept any block that conforms to the above criteria." },
  342.  
  343.   { &bagClass,    &collectionClass,
  344.       true,    true,    false,    1,
  345.       "Bag",        "contents",    nil,    nil,
  346.       "My instances are unordered collections of objects.  You can think\n\
  347. of me as a set with a memory; that is, if the same object is added to me\n\
  348. twice, then I will report that that element has been stored twice." },
  349.  
  350.   { &mappedCollectionClass,    &collectionClass,
  351.       true,    true,    false,    2,
  352.       "MappedCollection",    "domain map",    nil,    nil,
  353.       nil },
  354.  
  355.   { &setClass,    &collectionClass,
  356.       true,    true,    true,    1,
  357.       "Set",        "tally",    nil,    nil,
  358.       "I am the typical set object; I can store any objects uniquely.  I\n\
  359. use the = operator to determine duplication of objects." },
  360.  
  361.   { &dictionaryClass,    &setClass,
  362.       true,    true,    true,    0,
  363.       "Dictionary",    nil,    nil,    nil,
  364.       "I implement a dictionary, which is an object that is indexed by \n\
  365. unique objects (typcially instances of Symbol), and associates another \n\
  366. object with that index.  I use the equality operator = to determine \n\
  367. equality of indices." },
  368.  
  369.   { &identityDictionaryClass,        &dictionaryClass,
  370.       true,    true,    true,    1,
  371.       "IdentityDictionary",    "values",    nil,    nil,
  372.       "I am similar to dictionary, except that my representation is \n\
  373. different, and I use the object identity comparision message == to \n\
  374. determine equivalence of indices." },
  375.  
  376.   /* MUST have the same structure as dictionary; they're used interchangeably
  377.    * within the C portion of the system */
  378.   { &systemDictionaryClass,        &dictionaryClass,
  379.       true,    true,    true,    0, 
  380.       "SystemDictionary",    nil,    nil,    nil,
  381.       nil },
  382.  
  383.   { &streamClass,        &objectClass,
  384.       true,    true,    false,    0,
  385.       "Stream",        nil,    nil,    nil,
  386.       nil },
  387.  
  388.   { &tokenStreamClass,        &streamClass,
  389.       true,    true,    false,    1,
  390.       "TokenStream",        "charStream",    nil,    nil,
  391.       "I am not a typical part of the Smalltalk kernel class hierarchy.\n\
  392. I operate on a stream of characters and return distinct \n\
  393. (whitespace-delimited) groups of characters." },
  394.  
  395.   { &positionableStreamClass,    &streamClass,
  396.       true,    true,    false,    4,
  397.       "PositionableStream",    "collection ptr endPtr access",    nil,    nil,
  398.       nil },
  399.  
  400.   { &readStreamClass,        &positionableStreamClass,
  401.       true,    true,    false,    0,
  402.       "ReadStream",    nil,    nil,    nil,
  403.       nil },
  404.  
  405.   { &writeStreamClass,        &positionableStreamClass,
  406.       true,    true,    false,    1,
  407.       "WriteStream",    "maxSize",    nil,    nil,
  408.       nil },
  409.  
  410.   { &readWriteStreamClass,    &writeStreamClass,
  411.       true,    true,    false,    0,
  412.       "ReadWriteStream",    nil,    nil,    nil,
  413.       nil },
  414.  
  415.   { &fileStreamClass,        &readWriteStreamClass,
  416.       true,    true,    false,    2,
  417.       "FileStream",    "file name",        nil,    nil,
  418.       "My instances are what conventional programmers think of as files.\n\
  419. My instance creation methods accept the name of a disk file (or any named \n\
  420. file object, such as /dev/rmt0 on UNIX or MTA0: on VMS)." },
  421.  
  422.   { &randomClass,        &streamClass,
  423.       true,    true,    false,    1,
  424.       "Random",        "seed",        nil,    nil,
  425.       nil },
  426.  
  427.   { &undefinedObjectClass,        &objectClass,
  428.       true,    true,    false,    0,
  429.       "UndefinedObject",    nil,    nil,    nil,
  430.       "I have the questionable distinction of being a class with only one\n\
  431. instance, which is the object \"nil\".  I suspect that I should be sent\n\
  432. messages when errors occur, but currently I am not." },
  433.  
  434.   { &booleanClass,        &objectClass,
  435.       true,    true,    false,    0,
  436.       "Boolean",    nil,    nil,    nil,
  437.       nil },
  438.  
  439.   { &falseClass,        &booleanClass,
  440.       true,    true,    false,    1,
  441.       "False",        "truthValue",    nil,    nil, /* ### what's the inst var name in ST-80? */
  442.       nil },
  443.  
  444.   { &trueClass,        &booleanClass,
  445.       true,    true,    false,    1,
  446.       "True",        "truthValue",    nil,    nil, /* ### what's the inst var name in ST-80? */
  447.       nil },
  448.  
  449.   { &processorSchedulerClass,    &objectClass,
  450.       true,    true,    false,    2,
  451.       "ProcessorScheduler",    "processLists activeProcess",    nil,    nil,
  452.       nil },
  453.  
  454.   { &delayClass,    &objectClass,
  455.       true,    true,    false,    0, /* ### wrong */
  456.       "Delay",    nil,    nil,    nil,
  457.       nil },
  458.  
  459.   { &sharedQueueClass,    &objectClass,
  460.       true,    true,    false,    3, 
  461.       "SharedQueue",    "queueSem valueReady queue",    nil,    nil,
  462.       nil },
  463.  
  464.   /* Change this, classDescription, or Class, and you must change 
  465.    * the implementaion of newMetaclass some */
  466.   { &behaviorClass,        &objectClass,
  467.       true,    true,    false,    4,
  468.       "Behavior",    "superClass subClasses methodDictionary instanceSpec",
  469.       nil,    nil,
  470.       nil },
  471.  
  472.   { &classDescriptionClass,        &behaviorClass,
  473.       true,    true,    false,    4,
  474.       "ClassDescription",    "name comment instanceVariables category",
  475.       nil,    nil,
  476.       nil },
  477.  
  478.   { &classClass,        &classDescriptionClass,
  479.       true,    true,    false,    2,
  480.       "Class",    "classVariables sharedPools",    nil,    nil,
  481.       nil },
  482.  
  483.   { &metaclassClass,        &classDescriptionClass,
  484.       true,    true,    false,    1,
  485.       "Metaclass",    "instanceClass",    nil,    nil,
  486.       nil },
  487.  
  488.   { &methodContextClass,        &objectClass,
  489.       true,    true,    true,    7,
  490.       "MethodContext",    "sender ip sp method block selector receiver",    nil,    nil,
  491.       nil },
  492.  
  493.   { &blockContextClass,        &objectClass,
  494.       true,    true,    true,    7,
  495.       "BlockContext",    "caller ip sp numArgs initialIP selector home",    nil,
  496.      nil,
  497.       nil },
  498.  
  499. /***********************************************************************
  500.  *
  501.  *    End of Standard Smalltalk Class definitions.  The definitions below are
  502.  *    specific to GNU Smalltalk.
  503.  *
  504.  ***********************************************************************/
  505.  
  506.   { &cObjectClass,        &objectClass,
  507.       false,    true,    true,    0,
  508.       "CObject",    nil,    nil,    nil,
  509.       "I am not part of the standard Smalltalk kernel class hierarchy.\n\
  510. My instances contain values that are not interpreted by the Smalltalk \n\
  511. system; they frequently hold \"pointers\" to data outside of the Smalltalk\n\
  512. environment.  The C callout mechanism allows my instances to be transformed\n\
  513. into their corresponding C values for use in external routines." },
  514.  
  515.   { &cFuncDescriptorClass,    &objectClass,
  516.       true,    true,    true,    4,
  517.       "CFunctionDescriptor",    "cFunction cFunctionName returnType numFixedArgs",
  518.       nil,    nil,
  519.       nil },
  520.  
  521.   { &memoryClass,        &objectClass,
  522.       false,    true,    true,    0,
  523.       "Memory",        nil,    nil,    nil,
  524.       nil },
  525.  
  526.   { &byteMemoryClass,        &memoryClass,
  527.       false,    false,    true,    0,
  528.       "ByteMemory",    nil,    nil,    nil,
  529.       nil },
  530.  
  531.   { &wordMemoryClass,        &memoryClass,
  532.       false,    true,    true,    0,
  533.       "WordMemory",    nil,    nil,    nil,
  534.       nil },
  535.  
  536.   { &methodInfoClass,        &objectClass,
  537.       true,    true,    false,    2,
  538.       "MethodInfo",    "sourceCode category",    nil,    nil,
  539.       nil },
  540.  
  541.   { &fileSegmentClass,        &objectClass,
  542.       true,    true,    false,    3,
  543.       "FileSegment",    "fileName startPos length",    nil,    nil,
  544.       nil },
  545.  
  546.   { nil }
  547.  
  548. /* Smalltalk classes not defined:
  549.    Fraction
  550.    SmallInteger, LargeInteger
  551.    Bitmap, DisplayBitmap, RunArray
  552.    Text
  553.    FileDirectory, FilePage (probably never will be defined)
  554.    Point, Rectangle, BitBlt, CharacterScanner, Pen 
  555.    DisplayObject hierarchy
  556.  */
  557.  
  558. };
  559.  
  560.  
  561. /*
  562.  *    initDictionary()
  563.  *
  564.  * Description
  565.  *
  566.  *    Creates the kernel classes of the Smalltalk system.  Operates in two
  567.  *    passes: pass1 creates the class objects, but they're not completely
  568.  *    initialized.  pass2 finishes the initialization process.  The garbage
  569.  *    collector can NOT run during this time.
  570.  *
  571.  */
  572. void initDictionary()
  573. {
  574.   Metaclass    objectMetaclass; /* the metaclass of class Object */
  575.  
  576.   createClassesPass1();
  577.  
  578.   initCharTable();        /* we can do this now that char class def'd */
  579.   initNil();
  580.   initBooleans();
  581.  
  582.   initSmalltalkDictionary();
  583.  
  584.   createClassesPass2();
  585.  
  586.   initSTDIOObjects();
  587. }
  588.  
  589. static void createClassesPass1()
  590. {
  591.   ClassInfo    *ci;
  592.   OOP        parentClassOOP;
  593.  
  594.   /* Because all of the classes in classInfo are in the root set, we
  595.    * never need to validate them */
  596.   for (ci = classInfo; ci->classVar; ci++) {
  597.     if (ci->superClassPtr == nil) {
  598.       parentClassOOP = (OOP)nil;
  599.     } else {
  600.       parentClassOOP = *ci->superClassPtr;
  601.     }
  602.       
  603.     *ci->classVar = newClass(parentClassOOP, ci->isPointers, ci->isWords,
  604.                  ci->isIndexable, ci->numFixedFields);
  605.   }
  606. }
  607.  
  608. /* runs before GC turned on */
  609. static void  createClassesPass2()
  610. {
  611.   ClassInfo    *ci;
  612.   OOP        classOOP, superClassOOP;
  613.   Class        class, superClass;
  614.   long        index;
  615.  
  616.   /* Because all of the classes in classInfo are in the root set, we
  617.    * never need to validate them */
  618.   for (ci = classInfo; ci->classVar; ci++) {
  619.     classOOP = *ci->classVar;
  620.     class = (Class)oopToObj(classOOP);
  621.     class->name = internString(ci->name);
  622.     addSmalltalk(ci->name, classOOP);
  623.     class->methodDictionary = nilOOP;
  624.     index = toInt(class->subClasses);
  625.     if (classOOP == classClass) {
  626.       /*
  627.        * Object class being a subclass of Class is not an apparent link,
  628.        * and so the index which is the number of subclasses of the class
  629.        * is off by one.  We correct that here.
  630.        */
  631.       index++;
  632.     }
  633.     class->subClasses = arrayNew(index);
  634.     if (index > 0) {
  635.       arrayAtPut(class->subClasses, 1, fromInt(index));
  636.     }
  637.     if (classOOP == classClass) {
  638.       /*
  639.        * we don't want the meta class to have a subclass if we're special
  640.        * casing Object class, so back off the number of sub classes for
  641.        * the meta class.
  642.        */
  643.       index--;
  644.     }
  645.     if (classOOP == objectClass) { /* is this Object? */
  646.       /* nilOOP wasn't available during pass1, but now it is */
  647.       class->superClass = nilOOP;
  648.     } else {
  649.       /* hack the parent's subclass array */
  650.       superClassOOP = class->superClass;
  651.       addSubClass(superClassOOP, classOOP);
  652.       if (classOOP == classClass) {
  653.     /* here's where we patch in Object class is-a-subclass-of Class */
  654.     superClass = (Class)oopToObj(oopClass(objectClass));
  655.     superClass->superClass = classOOP;
  656.     addSubClass(classOOP, oopClass(objectClass));
  657.       }
  658.     }
  659.     class->objClass = newMetaclass(classOOP, index);
  660.     class->instanceVariables =
  661.       makeInstanceVariableArray(class->superClass, ci->instVarNames);
  662.     class->classVariables = makeClassVariableDictionary(class->superClass,
  663.                             ci->classVarNames);
  664.     class->sharedPools = makePoolArray(class->superClass, ci->sharedPoolNames);
  665.     if (ci->comment) {
  666.       class->comment = stringNew(ci->comment);
  667.     } else {
  668.       class->comment = nilOOP;    /* mark for later use */
  669.     }
  670.  
  671.     class->category = nilOOP;    /* not used yet. */
  672.   }
  673. }
  674.  
  675. /* runs before GC turned on */
  676. static OOP newMetaclass(classOOP, numSubClasses)
  677. OOP    classOOP;
  678. int    numSubClasses;
  679. {
  680.   OOP        superClassOOP, metaclassOOP;
  681.   int        index;
  682.   Metaclass    metaclass;
  683.  
  684.   metaclass = (Metaclass)newInstance(metaclassClass);
  685.   metaclassOOP = allocOOP(metaclass);
  686.   superClassOOP = superClass(classOOP);
  687.  
  688.   if (classOOP == objectClass) {
  689.     /* Object case: make this be Class to close the circularity */
  690.     metaclass->superClass = classClass;
  691.   } else {
  692.     metaclass->superClass = oopClass(superClassOOP);
  693.     addSubClass(metaclass->superClass, metaclassOOP);
  694.   }
  695.  
  696.   /* the specifications here should match what a class should have: instance
  697.      variable names, the right number of instance variables, etc.  We could
  698.      take three passes, and use the instance variable spec for classes once
  699.      it's established, but it's easier to create them here by hand */
  700.   metaclass->name = nilOOP;
  701.   metaclass->comment = nilOOP;
  702.   metaclass->instanceVariables = 
  703.       makeInstanceVariableArray(nilOOP, 
  704. "superClass subClasses methodDictionary instanceSpec \
  705. name comment instanceVariables category \
  706. classVariables sharedPools");
  707.  
  708.   metaclass->category = nilOOP;
  709.   metaclass->subClasses = arrayNew(numSubClasses);
  710.   if (numSubClasses > 0) {
  711.     arrayAtPut(metaclass->subClasses, 1, fromInt(numSubClasses));
  712.   }
  713.   metaclass->methodDictionary = nilOOP;
  714.   metaclass->instanceSpec.intMark = 1;
  715.   metaclass->instanceSpec.isPointers = 1;
  716.   metaclass->instanceSpec.isWords = 1;
  717.   metaclass->instanceSpec.isIndexable = 0;
  718.   metaclass->instanceSpec.numFixedFields = 
  719.     (sizeof(struct ClassStruct) - sizeof(ObjectHeader))/sizeof(OOP);
  720.  
  721.   metaclass->instanceClass = classOOP;
  722.  
  723.   return (metaclassOOP);
  724. }
  725.  
  726. static void addSubClass(superClassOOP, subClassOOP)
  727. OOP    superClassOOP, subClassOOP;
  728. {
  729.   ClassDescription superClass;
  730.   int        index;
  731.  
  732.   superClass = (ClassDescription)oopToObj(superClassOOP);
  733.  
  734.   if (numOOPs(oopToObj(superClass->subClasses)) > 0) {
  735.     index = toInt(arrayAt(superClass->subClasses, 1));
  736.     arrayAtPut(superClass->subClasses, 1, fromInt(index - 1));
  737.     arrayAtPut(superClass->subClasses, index, subClassOOP);
  738.   } else {
  739.     errorf("Attempt to add subclass to zero sized class");
  740.   }
  741. }
  742.  
  743. /*
  744.  *    static void initSmalltalkDictionary()
  745.  *
  746.  * Description
  747.  *
  748.  *    This creates the SystemDictionary called Smalltalk and initializes some
  749.  *    of the variables in it.
  750.  *
  751.  */
  752. static void initSmalltalkDictionary()
  753. {
  754.   OOP        cFunctionDescsDictionary;
  755.   char            fullVersionString[200];
  756.  
  757.   symbolTable = arrayNew(INITIAL_SYMBOL_TABLE_SIZE);
  758.  
  759.   smalltalkDictionary = systemDictionaryNew();
  760.   addSmalltalk("Smalltalk",        smalltalkDictionary);
  761.   cFunctionDescsDictionary = dictionaryNew();
  762.   addSmalltalk("CFunctionDescs",    cFunctionDescsDictionary);
  763.  
  764.   sprintf(fullVersionString, "Smalltalk version %s", versionString);
  765.   addSmalltalk("Version", stringNew(fullVersionString));
  766.  
  767. #ifdef BIG_ENDIAN
  768.   addSmalltalk("Bigendian", trueOOP);
  769. #else
  770.   addSmalltalk("Bigendian", falseOOP);
  771. #endif
  772.  
  773.   addSmalltalk("KernelInitialized", falseOOP);
  774.  
  775.   addSmalltalk("SymbolTable", symbolTable);
  776.  
  777.   initProcessSystem();
  778.  
  779.   addSmalltalk("Processor",        processorOOP);
  780. }
  781.  
  782. static void addSmalltalk(globalName, globalValue)
  783. char    *globalName;
  784. OOP    globalValue;
  785. {
  786.   dictionaryAtPut(smalltalkDictionary, internString(globalName), globalValue);
  787. }
  788.  
  789.  
  790. OOP findClass(classNameOOP)
  791. OOP    classNameOOP;
  792. {
  793.   return (dictionaryAt(smalltalkDictionary, classNameOOP));
  794. }
  795.  
  796. void initSTDIOObjects()
  797. {
  798.   addSTDIOObject(stdin, "stdin");
  799.   addSTDIOObject(stdout, "stdout");
  800.   addSTDIOObject(stderr, "stderr");
  801. }
  802.  
  803. static void addSTDIOObject(file, fileObjectName)
  804. FILE    *file;
  805. char    *fileObjectName;
  806. {
  807.   OOP        fileOOP, fileStreamOOP;
  808.  
  809.   fileOOP = cObjectNew(file);
  810.   fileStreamOOP = allocOOP(instantiate(fileStreamClass));
  811.   setFileStreamFile(fileStreamOOP, fileOOP, stringNew(fileObjectName));
  812.  
  813.   addSmalltalk(fileObjectName, fileStreamOOP);
  814. }
  815.  
  816.  
  817. /* runs before GC turned on */
  818. static OOP newClass(superClassOOP, isPointers, isWords, isIndexable,
  819.             numFixedFields)
  820. OOP    superClassOOP;
  821. Boolean    isPointers, isWords, isIndexable;
  822. int    numFixedFields;
  823. {
  824.   Class        class, superClass;
  825.   InstanceSpec    superInstanceSpec;
  826.  
  827.   if (superClassOOP != (OOP)nil) {
  828.     /* adjust the number of instance variables to account for inheritance */
  829.     superInstanceSpec = classInstanceSpec(superClassOOP);
  830.     numFixedFields += superInstanceSpec.numFixedFields;
  831.     superClass = (Class)oopToObj(superClassOOP);
  832.     superClass->subClasses = fromInt(toInt(superClass->subClasses) + 1);
  833.   }
  834.  
  835.   class            = (Class)allocObj(sizeof(struct ClassStruct));
  836.   class->objSize    = ROUNDED_WORDS(sizeof(struct ClassStruct));
  837.   class->objClass    = nil;
  838.   class->superClass            = superClassOOP;
  839.   class->instanceSpec.intMark        = 1;
  840.   class->instanceSpec.isPointers    = isPointers;
  841.   class->instanceSpec.isWords        = isWords;
  842.   class->instanceSpec.isIndexable    = isIndexable;
  843.   class->instanceSpec.numFixedFields    = numFixedFields;
  844.   class->subClasses            = fromInt(0);
  845.  
  846.   return (allocOOP(class));
  847. }
  848.  
  849.  
  850. void setComment(classDescOOP, commentOOP)
  851. OOP    classDescOOP, commentOOP;
  852. {
  853.     Class    class;
  854.  
  855.     class = (Class)oopToObj(classDescOOP);
  856.     class->comment = commentOOP;
  857. }
  858.  
  859.  
  860. void printOOPConstructor(oop)
  861. OOP    oop;
  862. {
  863.   InstanceSpec    instanceSpec;
  864.   OOP        classOOP;
  865.   Class        class;
  866.  
  867.   if (isAMetaclass(oop)) {
  868.     classOOP = findAnInstance(oop);
  869.     if (isNil(classOOP)) {
  870.       printf("<name unknown>");        /* we're a nameless class */
  871.     } else {
  872.       printClassName(classOOP);
  873.     }
  874.     printf(" class");
  875.     return;
  876.   }
  877.  
  878.   if (isAClass(oop)) {
  879.     printClassName(oop);
  880.     return;
  881.   }
  882.  
  883.   printOOPClassName(oop);
  884.  
  885.   classOOP = oopClass(oop);
  886.   instanceSpec = classInstanceSpec(classOOP);
  887.   if (instanceSpec.isIndexable) {
  888.     printf(" new: %d ", numIndexableFields(oop));
  889.   } else {
  890.     printf(" new ");
  891.   }
  892.  
  893.   /* ### still need to print the initialization for instance variables */
  894.   if (regressionTesting) {
  895.     printf("\"<%#x>\"", 0);
  896.   } else {
  897.     printf("\"<%#x>\"", oop);
  898.   }
  899. }
  900.  
  901. Boolean isAMetaclass(oop)
  902. OOP    oop;
  903. {
  904.   if (isInt(oop)) {
  905.     return (false);
  906.   }
  907.  
  908.   return (oopClass(oop) == metaclassClass);
  909. }
  910.  
  911. Boolean isAClass(oop)
  912. OOP    oop;
  913. {
  914.   OOP        classOOP;
  915.  
  916.   if (isInt(oop)) {
  917.     return (false);
  918.   }
  919.  
  920.   classOOP = oopClass(oop);
  921.   return (oopClass(classOOP) == metaclassClass);
  922. }
  923.  
  924. static void printOOPClassName(oop)
  925. OOP    oop;
  926. {
  927.   OOP        classOOP;
  928.   Class        class;
  929.  
  930.   if (isInt(oop)) {
  931.     classOOP = integerClass;
  932.   } else {
  933.     classOOP = oopClass(oop);
  934.   }
  935.  
  936.   printClassName(classOOP);
  937. }
  938.  
  939.  
  940. static void printClassName(classOOP)
  941. OOP    classOOP;
  942. {
  943.   Class        class;
  944.  
  945.   class = (Class)oopToObj(classOOP);
  946.   if (isNil(class->name)) {
  947.     printf("<no class name>");
  948.   } else {
  949.     printString(class->name);
  950.   }
  951. }
  952.  
  953. OOP getClassSymbol(classOOP)
  954. OOP    classOOP;
  955. {
  956.   Class        class;
  957.  
  958.   class = (Class)oopToObj(classOOP);
  959.   return (class->name);
  960.   /* this is the case when we have a metaclass,
  961.      ??? I don't think that this is right, but I don't know what else to do
  962.      here */
  963. }
  964.  
  965.  
  966. /*
  967.  *    OOP metaclassInstance(metaclassOOP)
  968.  *
  969.  * Description
  970.  *
  971.  *    Returns the class that is the sole instance of the meta class
  972.  *    "metaclassOOP".
  973.  *
  974.  * Inputs
  975.  *
  976.  *    metaclassOOP: 
  977.  *        An OOP that should be a meta class.
  978.  *
  979.  * Outputs
  980.  *
  981.  *    The class that's the sole instance of "metaclassOOP".
  982.  */
  983. OOP metaclassInstance(metaclassOOP)
  984. OOP    metaclassOOP;
  985. {
  986.   return (((Metaclass)oopToObj(metaclassOOP))->instanceClass);
  987. }
  988.  
  989. /*
  990.  *    OOP validClassMethodDictionary(classOOP)
  991.  *
  992.  * Description
  993.  *
  994.  *    Gets the method dictionary associated with "classOOP", and returns it.
  995.  *    If the methodDictionary associated with "classOOP" is nil, one is
  996.  *    created and installed into that class.
  997.  *
  998.  * Inputs
  999.  *
  1000.  *    classOOP: 
  1001.  *        Class to get the method dictionary of.
  1002.  *
  1003.  * Outputs
  1004.  *
  1005.  *    A non-nil object of type MethodDictionary.
  1006.  */
  1007. OOP validClassMethodDictionary(classOOP)
  1008. OOP    classOOP;
  1009. {
  1010.   Class        class;
  1011.  
  1012.   /* ??? check for non-class objects */
  1013.   class = (Class)oopToObj(classOOP);
  1014.   if (isNil(class->methodDictionary)) {
  1015.     class->methodDictionary = identityDictionaryNew();
  1016.   }
  1017.  
  1018.   return (class->methodDictionary);
  1019. }
  1020.  
  1021. OOP classMethodDictionary(classOOP)
  1022. OOP    classOOP;
  1023. {
  1024.   Class        class;
  1025.  
  1026.   class = (Class)oopToObj(classOOP);
  1027.   return (class->methodDictionary);
  1028. }
  1029.  
  1030. OOP classVariableDictionary(classOOP)
  1031. OOP    classOOP;
  1032. {
  1033.   Class        class;
  1034.  
  1035.   /* ??? check for non-class objects */
  1036.   class = (Class)oopToObj(classOOP);
  1037.   return (class->classVariables);
  1038. }
  1039.  
  1040. OOP instanceVariableArray(classOOP)
  1041. OOP    classOOP;
  1042. {
  1043.   Class        class;
  1044.  
  1045.   /* ??? check for non-class  objects */
  1046.   class = (Class)oopToObj(classOOP);
  1047.   return (class->instanceVariables);
  1048. }
  1049.  
  1050. OOP sharedPoolDictionary(classOOP)
  1051. OOP    classOOP;
  1052. {
  1053.   Class        class;
  1054.  
  1055.   /* ??? check for non-class objects */
  1056.   class = (Class)oopToObj(classOOP);
  1057.   return (class->sharedPools);
  1058. }
  1059.  
  1060.  
  1061. OOP findSharedPoolVariable(classOOP, symbol)
  1062. OOP    classOOP, symbol;
  1063. {
  1064.   OOP        assocOOP, poolDictionaryOOP;
  1065.   Class        class;
  1066.   int        numPools, i;
  1067.  
  1068.   /* ??? check for non-class objects */
  1069.   class = (Class)oopToObj(classOOP);
  1070.  
  1071.   /* ??? shared pools are currently represented as arrays, from the book
  1072.      I conjecture that their shared pools are implemented as sets. */
  1073.   numPools = numOOPs(oopToObj(class->sharedPools));
  1074.   for (i = 0; i < numPools; i++) {
  1075.     poolDictionaryOOP = arrayAt(class->sharedPools, i+1);
  1076.     assocOOP = dictionaryAssociationAt(poolDictionaryOOP, symbol);
  1077.     if (!isNil(assocOOP)) {
  1078.       return (assocOOP);
  1079.     }
  1080.   }
  1081.  
  1082.   return (nilOOP);
  1083. }
  1084.  
  1085. /*
  1086.  *    Boolean isAKindOf(memberOOP, classOOP)
  1087.  *
  1088.  * Description
  1089.  *
  1090.  *    Checks to see if "memberOOP" is a subclass of "classOOP", returning
  1091.  *    true if it is.
  1092.  *
  1093.  * Inputs
  1094.  *
  1095.  *    memberOOP: 
  1096.  *        A class OOP that's to be checked for (sub)class membership.
  1097.  *    classOOP: 
  1098.  *        A class OOP that's the conjectured (super)class.
  1099.  *
  1100.  * Outputs
  1101.  *
  1102.  *    True if "memberOOP" is a (sub)class of "classOOP".
  1103.  */
  1104. Boolean isAKindOf(memberOOP, classOOP)
  1105. OOP    memberOOP, classOOP;
  1106. {
  1107.   for ( ; !isNil(memberOOP); memberOOP = superClass(memberOOP)) {
  1108.     if (memberOOP == classOOP) {
  1109.       return (true);
  1110.     }
  1111.   }
  1112.   
  1113.   return (false);
  1114. }
  1115.  
  1116. /*
  1117.  *    OOP superClass(classOOP)
  1118.  *
  1119.  * Description
  1120.  *
  1121.  *    Given an OOP for a class, this routine returns the superclass OOP for
  1122.  *    that class.  Note: this is NOT the metaclass, this is the parent class.
  1123.  *
  1124.  * Inputs
  1125.  *
  1126.  *    classOOP: 
  1127.  *        OOP that references a class.
  1128.  *
  1129.  * Outputs
  1130.  *
  1131.  *    Superclass of "classOOP".  A class OOP or nil OOP.
  1132.  */
  1133. OOP superClass(classOOP)
  1134. OOP    classOOP;
  1135. {
  1136.   return (((Class)oopToObj(classOOP))->superClass);
  1137. }
  1138.  
  1139. OOP findClassMethod(classOOP, selector)
  1140. OOP    classOOP, selector;
  1141. {
  1142.   Class        class;
  1143.   IdentityDictionary methodDictionary;
  1144.   OOP        methodDictionaryOOP;
  1145.   int        index;
  1146.  
  1147.   class = (Class)oopToObj(classOOP);
  1148.   methodDictionaryOOP = class->methodDictionary;
  1149.   if (isNil(methodDictionaryOOP)) {
  1150.     return (nilOOP);
  1151.   }
  1152.  
  1153.   index = identityDictionaryFindKeyOrNil(methodDictionaryOOP, selector);
  1154.   methodDictionary = (IdentityDictionary)oopToObj(methodDictionaryOOP);
  1155.  
  1156.   return (arrayAt(methodDictionary->values, index+1));
  1157. }
  1158.  
  1159. static OOP identityDictionaryNew()
  1160. {
  1161.   IdentityDictionary identityDictionary;
  1162.  
  1163.   identityDictionary =
  1164.     (IdentityDictionary)instantiateWith(identityDictionaryClass,
  1165.                        INITIAL_DICTIONARY_SIZE);
  1166.   identityDictionary->tally = fromInt(0);
  1167.   identityDictionary->values = arrayNew(INITIAL_DICTIONARY_SIZE);
  1168.  
  1169.   return (allocOOP(identityDictionary));
  1170. }
  1171.  
  1172. OOP identityDictionaryAtPut(identityDictionaryOOP, keyOOP, valueOOP)
  1173. OOP    identityDictionaryOOP, keyOOP, valueOOP;
  1174. {
  1175.   IdentityDictionary identityDictionary;
  1176.   Array        valuesArray;
  1177.   long        index;
  1178.   
  1179.   index = identityDictionaryFindKeyOrNil(identityDictionaryOOP, keyOOP);
  1180.   identityDictionary = (IdentityDictionary)oopToObj(identityDictionaryOOP);
  1181.  
  1182.   if (isNil(identityDictionary->keys[index])) {
  1183.     identityDictionary->tally = incrInt(identityDictionary->tally);
  1184.   }
  1185.   prepareToStore(identityDictionaryOOP, keyOOP);
  1186.   identityDictionary->keys[index] = keyOOP;
  1187.   valuesArray = (Array)oopToObj(identityDictionary->values);
  1188.   prepareToStore(identityDictionary->values, valueOOP);
  1189.   valuesArray->elements[index] = valueOOP;
  1190.  
  1191.   return (keyOOP);
  1192. }
  1193.  
  1194. static IdentityDictionary growIdentityDictionary(identityDictionaryOOP)
  1195. OOP    identityDictionaryOOP;
  1196. {
  1197.   IdentityDictionary oldIdentityDictionary, identityDictionary;
  1198.   Array        values, oldValues;
  1199.   OOP        key, valuesOOP, oldValuesOOP, oldOOP;
  1200.   long        oldNumFields, numFields, i, index;
  1201.  
  1202.   oldIdentityDictionary = (IdentityDictionary)oopToObj(identityDictionaryOOP);
  1203.   oldNumFields = numOOPs(oldIdentityDictionary) - OBJ_HEADER_SIZE_WORDS;
  1204.  
  1205.   numFields = oldNumFields * 2;
  1206.  
  1207.   identityDictionary =
  1208.     (IdentityDictionary)instantiateWith(identityDictionaryClass, numFields);
  1209.   maybeMoveOOP(identityDictionaryOOP); /* make sure that it's valid */
  1210.   oldIdentityDictionary = (IdentityDictionary)oopToObj(identityDictionaryOOP);
  1211.   identityDictionary->tally = oldIdentityDictionary->tally;
  1212.   setOOPObject(identityDictionaryOOP, identityDictionary);
  1213.   identityDictionary = (IdentityDictionary)oopToObj(identityDictionaryOOP);
  1214.  
  1215.   oldValuesOOP = oldIdentityDictionary->values;
  1216.   maybeMoveOOP(oldValuesOOP);    /* ### not sure that this is necessary */
  1217.   oldValues = (Array)oopToObj(oldValuesOOP);
  1218.   valuesOOP = arrayNew(numFields);
  1219.   values = (Array)oopToObj(valuesOOP);
  1220.   identityDictionary->values = valuesOOP;
  1221.  
  1222.   /* rehash all associations from old dictionary into new one */
  1223.   for (i = 0; i < oldNumFields; i++) {
  1224.     key = oldIdentityDictionary->keys[i];
  1225.     if (!isNil(key)) {
  1226.       index = identityDictionaryFindKeyOrNil(identityDictionaryOOP, key);
  1227.       maybeMoveOOP(key);
  1228.       identityDictionary->keys[index] = key;
  1229.       oldOOP = oldValues->elements[i];
  1230.       maybeMoveOOP(oldOOP);
  1231.       values->elements[index] = oldOOP;
  1232.     }
  1233.   }
  1234.  
  1235.   maybeMoveOOP(identityDictionary->values);
  1236.   maybeMoveOOP(identityDictionaryOOP);
  1237.   return (identityDictionary);
  1238. }
  1239.  
  1240. int identityDictionaryFindKeyOrNil(identityDictionaryOOP, keyOOP)
  1241. OOP    identityDictionaryOOP, keyOOP;
  1242. {
  1243.   IdentityDictionary identityDictionary;
  1244.   register long    index, count;
  1245.   long        numFields;
  1246.   
  1247.   identityDictionary = (IdentityDictionary)oopToObj(identityDictionaryOOP);
  1248.   for ( ; ; ) {
  1249. /* ### WRONG WRONG WRONG ### this is not accounting for the instance
  1250.    variables*/
  1251.     numFields = numOOPs(identityDictionary) - OBJ_HEADER_SIZE_WORDS;
  1252.     index = hash(keyOOP);
  1253.     index %= numFields;
  1254.     count = numFields;
  1255.  
  1256.     /* linear reprobe -- it is simple and guaranteed */
  1257.     for ( ; count > 0; index = (index + 1) % numFields, count--) {
  1258.       if (isNil(identityDictionary->keys[index])) {
  1259.     return (index);
  1260.       }
  1261.  
  1262.       if (identityDictionary->keys[index] == keyOOP) {
  1263.     return (index);
  1264.       }
  1265.     }
  1266.  
  1267.     /*
  1268.      * If we get to here, the dictionary is full, but we haven't found
  1269.      * the element that we're looking for.  Since we either return the
  1270.      * index of the element being sought, or the index of a nil element,
  1271.      * and the dictionary was full so that there was no nil element, we
  1272.      * grow the dictionary and scan it again.  We're guaranteed to exit
  1273.      * this loop via a return after at most two iterations.
  1274.      */
  1275.     identityDictionary = growIdentityDictionary(identityDictionaryOOP);
  1276.   }
  1277. }
  1278.  
  1279. /*
  1280.  *    pid(id)
  1281.  *
  1282.  * Description
  1283.  *
  1284.  *    Debug support routine.  Prints out the keys of an IdentityDictionary.
  1285.  *
  1286.  * Inputs
  1287.  *
  1288.  *    id    : an IdentityDictionary
  1289.  *
  1290.  */
  1291. pid(id)
  1292. IdentityDictionary id;
  1293. {
  1294.   int i;
  1295.  
  1296.   for (i = 0; i < toInt(id->tally); i++) {
  1297.     printf("%d: "); printObject(id->keys[i]); printf("\n");
  1298.   }
  1299. }
  1300.  
  1301. static OOP systemDictionaryNew()
  1302. {
  1303.   OOP        dictionaryOOP;
  1304.   Dictionary    dictionary;
  1305.  
  1306.   /* ^super new! */
  1307.   dictionaryOOP = dictionaryNew();
  1308.   dictionary = (Dictionary)oopToObj(dictionaryOOP);
  1309.   dictionary->objClass = systemDictionaryClass;
  1310.   return (dictionaryOOP);
  1311. }
  1312.  
  1313. OOP dictionaryNew()
  1314. {
  1315.   Dictionary    dictionary;
  1316.  
  1317.   dictionary = (Dictionary)instantiateWith(dictionaryClass,
  1318.                        INITIAL_DICTIONARY_SIZE);
  1319.   dictionary->tally = fromInt(0);
  1320.  
  1321.   return (allocOOP(dictionary));
  1322. }
  1323.  
  1324.  
  1325. int dictionarySize(dictionaryOOP)
  1326. OOP    dictionaryOOP;
  1327. {
  1328.   Dictionary    dictionary;
  1329.  
  1330.   dictionary = (Dictionary)oopToObj(dictionaryOOP);
  1331.   return (toInt(dictionary->tally));
  1332. }
  1333.  
  1334.  
  1335. OOP dictionaryAtPut(dictionaryOOP, keyOOP, valueOOP)
  1336. OOP    dictionaryOOP, keyOOP, valueOOP;
  1337. {
  1338.   OOP        associationOOP;
  1339.  
  1340.   associationOOP = associationNew(keyOOP, valueOOP);
  1341.   return (dictionaryAdd(dictionaryOOP, associationOOP));
  1342. }
  1343.  
  1344. OOP dictionaryAdd(dictionaryOOP, associationOOP)
  1345. OOP    dictionaryOOP,  associationOOP;
  1346. {
  1347.   long        index, size;
  1348.   Association    association;
  1349.   Dictionary    dictionary;
  1350.   OOP        value;
  1351.  
  1352.   association = (Association)oopToObj(associationOOP);
  1353.   dictionary = (Dictionary)oopToObj(dictionaryOOP);
  1354.   if (toInt(dictionary->tally) >= numOOPs(dictionary)-1) {
  1355.     dictionary = growDictionary(dictionaryOOP);
  1356.   }
  1357.  
  1358.   index = findKeyOrNil(dictionaryOOP, association->key);
  1359.   if (isNil(dictionary->assoc[index])) {
  1360.     prepareToStore(dictionaryOOP, associationOOP);
  1361.     dictionary->tally = incrInt(dictionary->tally);
  1362.     dictionary->assoc[index] = associationOOP;
  1363.   } else {
  1364.     value = associationValue(associationOOP);
  1365.     associationOOP = dictionary->assoc[index];
  1366.     setAssociationValue(associationOOP, value);
  1367.   }
  1368.  
  1369.   return (associationOOP);
  1370. }
  1371.  
  1372. /*
  1373.  *    static Dictionary growDictionary(dictionaryOOP)
  1374.  *
  1375.  * Description
  1376.  *
  1377.  *    Called when a dictionary becomes full, this routine replaces the
  1378.  *    dictionary instance that "dictionaryOOP" is pointing to with a new,
  1379.  *    larger dictionary, and returns this new dictionary as its value.
  1380.  *
  1381.  * Inputs
  1382.  *
  1383.  *    dictionaryOOP: 
  1384.  *        Object pointer to the dictionary that's to be expanded
  1385.  *
  1386.  * Outputs
  1387.  *
  1388.  *    New dictionary, with all of the old elements rehashed into it. 
  1389.  */
  1390. static Dictionary growDictionary(dictionaryOOP)
  1391. OOP    dictionaryOOP;
  1392. {
  1393.   Dictionary    oldDictionary, dictionary;
  1394.   long        oldNumFields, numFields, i, index;
  1395.   OOP        associationOOP;
  1396.   Association    association;
  1397.  
  1398.  
  1399.   oldDictionary = (Dictionary)oopToObj(dictionaryOOP);
  1400.   oldNumFields = numOOPs(oldDictionary) - 1;
  1401.  
  1402.   numFields = oldNumFields * 2;
  1403.  
  1404.   dictionary = (Dictionary)instantiateWith(oopClass(dictionaryOOP), numFields);
  1405.   dictionary->tally = oldDictionary->tally;
  1406.   maybeMoveOOP(dictionaryOOP);    /* make sure old dictionary is valid */
  1407.   oldDictionary = (Dictionary)oopToObj(dictionaryOOP);
  1408.   setOOPObject(dictionaryOOP, dictionary);
  1409.  
  1410.   /* rehash all associations from old dictionary into new one */
  1411.   for (i = 0; i < oldNumFields; i++) {
  1412.     if (!isNil(oldDictionary->assoc[i])) {
  1413.       associationOOP = oldDictionary->assoc[i];
  1414.       association = (Association)oopToObj(associationOOP);
  1415.       index = findKeyOrNil(dictionaryOOP, association->key);
  1416.       dictionary->assoc[index] = associationOOP;
  1417.       maybeMoveOOP(associationOOP);
  1418.     }
  1419.   }
  1420.  
  1421.   maybeMoveOOP(dictionaryOOP);
  1422.   return (dictionary);
  1423. }
  1424.  
  1425. /*
  1426.  *    OOP dictionaryCopy(dictionaryOOP)
  1427.  *
  1428.  * Description
  1429.  *
  1430.  *    Create and return an exact copy of "dictionaryOOP", which is a normal
  1431.  *    dictionary object.  This is a "shallow copy"; all the associations in
  1432.  *    the dictionary are the exact same ones that are in the original
  1433.  *    dictionary.  If passed nil, returns nil.
  1434.  *
  1435.  * Inputs
  1436.  *
  1437.  *    dictionaryOOP: 
  1438.  *        A dictionary object that a copy is to be made of.
  1439.  *
  1440.  * Outputs
  1441.  *
  1442.  *    An exact copy of the dictionary that we were passed.
  1443.  */
  1444. OOP dictionaryCopy(dictionaryOOP)
  1445. OOP    dictionaryOOP;
  1446. {
  1447.   Dictionary    oldDictionary, dictionary;
  1448.   long        numFields, i;
  1449.  
  1450.   if (isNil(dictionaryOOP)) {
  1451.     return (nilOOP);
  1452.   }
  1453.  
  1454.   oldDictionary = (Dictionary)oopToObj(dictionaryOOP);
  1455.   numFields = numOOPs(oldDictionary) - 1;
  1456.  
  1457.   /* ??? we may want to create a copy object routine that just mallocs and
  1458.      copies the contents verbatim; this routine would then be just a call to
  1459.      that routine. */
  1460.   dictionary = (Dictionary)instantiateWith(dictionaryClass, numFields);
  1461.   memcpy(dictionary, oldDictionary, oldDictionary->objSize << 2);
  1462.   for (i = 0; i < numFields; i++) {
  1463.     maybeMoveOOP(dictionary->assoc[i]);
  1464.   }
  1465.  
  1466.   return (allocOOP(dictionary));
  1467. }
  1468.  
  1469. OOP dictionaryAt(dictionaryOOP, keyOOP)
  1470. OOP    dictionaryOOP, keyOOP;
  1471. {
  1472.   OOP        assocOOP;
  1473.  
  1474.   assocOOP = dictionaryAssociationAt(dictionaryOOP, keyOOP);
  1475.  
  1476.   if (isNil(assocOOP)) {
  1477.     return (nilOOP);
  1478.   } else {
  1479.     return (associationValue(assocOOP));
  1480.   }
  1481. }
  1482.  
  1483. OOP dictionaryAssociationAt(dictionaryOOP, keyOOP)
  1484. OOP    dictionaryOOP, keyOOP;
  1485. {
  1486.   long        index;
  1487.   Dictionary    dictionary; 
  1488.  
  1489.   if (isNil(dictionaryOOP)) {
  1490.     return (nilOOP);
  1491.   }
  1492.  
  1493.   index = findKeyOrNil(dictionaryOOP, keyOOP);
  1494.   dictionary = (Dictionary)dictionaryOOP->object;
  1495.  
  1496.   return (dictionary->assoc[index]);
  1497. }
  1498.  
  1499. int findKeyOrNil(dictionaryOOP, keyOOP)
  1500. OOP    dictionaryOOP, keyOOP;
  1501. {
  1502.   long        index, numFields;
  1503.   Dictionary    dictionary; 
  1504.   OOP        associationOOP;
  1505.   Association    association;
  1506.  
  1507.   dictionary = (Dictionary)oopToObj(dictionaryOOP);
  1508.   numFields = numOOPs(dictionary) - 1;
  1509.   index = hash(keyOOP);
  1510.   index %= numFields;
  1511.  
  1512.   /* linear reprobe -- it is simple and guaranteed */
  1513.   for ( ; ; index = (index + 1) % numFields) {
  1514.     if (isNil(dictionary->assoc[index])) {
  1515.       return (index);
  1516.     }
  1517.  
  1518.     associationOOP = dictionary->assoc[index];
  1519.     association = (Association)associationOOP->object;
  1520.  
  1521.     if (equal(association->key, keyOOP)) {
  1522.       return (index);
  1523.     }
  1524.   }
  1525. }
  1526.  
  1527. OOP associationNew(key, value)
  1528. OOP    key, value;
  1529. {
  1530.   Association    association;
  1531.  
  1532.   association = (Association)newInstance(associationClass);
  1533.   maybeMoveOOP(key);
  1534.   maybeMoveOOP(value);
  1535.   association->key = key;
  1536.   association->value = value;
  1537.  
  1538.   return (allocOOP(association));
  1539. }
  1540.  
  1541. OOP associationValue(associationOOP)
  1542. OOP    associationOOP;
  1543. {
  1544.   return (((Association)oopToObj(associationOOP))->value);
  1545. }
  1546.  
  1547. void setAssociationValue(associationOOP, value)
  1548. OOP    associationOOP, value;
  1549. {
  1550.   prepareToStore(associationOOP, value);
  1551.   ((Association)oopToObj(associationOOP))->value = value;
  1552. }
  1553.  
  1554. void printAssociationKey(associationOOP)
  1555. OOP    associationOOP;
  1556. {
  1557.   Association    association;
  1558.  
  1559.   association = (Association)oopToObj(associationOOP);
  1560.   if (oopClass(association->key) != symbolClass) {
  1561.     printf("<unprintable key type>");
  1562.   } else {
  1563.     printSymbol(association->key);
  1564.   }
  1565. }
  1566.  
  1567. /*
  1568.  *    OOP instantiateOOPWith(classOOP, numIndexFields)
  1569.  *
  1570.  * Description
  1571.  *
  1572.  *    Returns an OOP for a newly allocated instance of "classOOP", with
  1573.  *    "numIndexFields" fields.  The OOP is adjusted to reflect any
  1574.  *    variance in size (such as a string that's shorter than a word boundary.
  1575.  *
  1576.  * Inputs
  1577.  *
  1578.  *    classOOP: 
  1579.  *        An OOP for the class to create the instance of.
  1580.  *    numIndexFields: 
  1581.  *        The number of index fields to create in the instance.  Must be
  1582.  *        >= 0.
  1583.  *
  1584.  * Outputs
  1585.  *
  1586.  *    A new OOP that holds the newly allocated instance, with possible
  1587.  *    correction for size.
  1588.  */
  1589. OOP instantiateOOPWith(classOOP, numIndexFields)
  1590. OOP    classOOP;
  1591. long    numIndexFields;
  1592. {
  1593.   Object    object;
  1594.   OOP        oop;
  1595.   InstanceSpec    instanceSpec;
  1596.  
  1597.   object = instantiateWith(classOOP, numIndexFields);
  1598.   oop = allocOOP(object);
  1599.   instanceSpec = classInstanceSpec(classOOP);
  1600.   if (!instanceSpec.isWords) {
  1601.     oop->emptyBytes = (4 - numIndexFields) & 3;
  1602.   }
  1603.  
  1604.   return (oop);
  1605. }
  1606.  
  1607. /*
  1608.  *    Object instantiateWith(classOOP, numIndexFields)
  1609.  *
  1610.  * Description
  1611.  *
  1612.  *    Returns a new, initialized instance with indexable fields.  If the
  1613.  *    instance contains pointers, they are initialized to nilOOP, else they
  1614.  *    are set to real zero.
  1615.  *
  1616.  * Inputs
  1617.  *
  1618.  *    classOOP: 
  1619.  *        Class to make an instance of.  An OOP.
  1620.  *    numIndexFields: 
  1621.  *        The number if indexed instance variables this instance is to
  1622.  *        have, possibly zero.  A long.
  1623.  *
  1624.  * Outputs
  1625.  *
  1626.  *    New instance with initialized, indexed instance variables.
  1627.  */
  1628. Object instantiateWith(classOOP, numIndexFields)
  1629. OOP    classOOP;
  1630. long    numIndexFields;
  1631. {
  1632.   Object    instance;
  1633.   InstanceSpec    instanceSpec;
  1634.   long        numBytes, OOPCount;
  1635.   register long i;
  1636.   register OOP    *oopPtr;
  1637.   
  1638.   instance = newInstanceWith(classOOP, numIndexFields);
  1639.   instanceSpec = classInstanceSpec(classOOP);
  1640.   if (instanceSpec.isPointers) {
  1641.     for (i = 0, oopPtr = instance->data,
  1642.      OOPCount = instanceSpec.numFixedFields + numIndexFields;
  1643.      i < OOPCount; i++) {
  1644.       *oopPtr++ = nilOOP;
  1645.     }
  1646.   } else {
  1647.     numBytes = instanceSpec.numFixedFields + numIndexFields;
  1648.     if (instanceSpec.isWords) {
  1649.       numBytes <<= 2;
  1650.     }
  1651.     bzero(instance->data, numBytes);
  1652.   }
  1653.   return (instance);
  1654. }
  1655.  
  1656. /*
  1657.  *    Object instantiate(classOOP)
  1658.  *
  1659.  * Description
  1660.  *
  1661.  *    Create and return a new instance of class "classOOP".  "classOOP" must
  1662.  *    be a class with no indexable fields.  The named instance variables of
  1663.  *    the new instance are initialized to nilObj, since fixed-field-only 
  1664.  *    objects can only have pointers.
  1665.  *
  1666.  * Inputs
  1667.  *
  1668.  *    classOOP: 
  1669.  *        An OOP for the class to create the instance of.
  1670.  *
  1671.  * Outputs
  1672.  *
  1673.  *    The new instance, with its fields initialized.
  1674.  */
  1675. Object instantiate(classOOP)
  1676. OOP    classOOP;
  1677. {
  1678.   Object    instance;
  1679.   InstanceSpec    instanceSpec;
  1680.   int        i;
  1681.  
  1682.   instance = newInstance(classOOP);
  1683.   instanceSpec = classInstanceSpec(classOOP);
  1684.   if (!instanceSpec.isPointers) {
  1685.     errorf("Class with non-pointer instance spec passed to instantiate");
  1686.   }
  1687.  
  1688.   for (i = 0; i < instanceSpec.numFixedFields; i++) {
  1689.     instance->data[i] = nilOOP;
  1690.   }
  1691.   return (instance);
  1692. }
  1693.  
  1694. Object newInstanceWith(classOOP, numIndexFields)
  1695. OOP    classOOP;
  1696. long    numIndexFields;
  1697. {
  1698.   Object    instance;
  1699.   int        numBytes;
  1700.   InstanceSpec    instanceSpec;
  1701.  
  1702.   numBytes = instanceSize(classOOP);
  1703.   instanceSpec = classInstanceSpec(classOOP);
  1704.   if (instanceSpec.isWords) {
  1705.     numIndexFields <<= 2;
  1706.   }
  1707.   numBytes += numIndexFields;
  1708.   numBytes = ROUNDED_WORDS(numBytes) << 2;
  1709.   instance = (Object)allocObj(numBytes);
  1710.   instance->objSize = numBytes >> 2;
  1711.   instance->objClass = classOOP;
  1712.   maybeMoveOOP(classOOP);
  1713.   return (instance);
  1714. }
  1715.  
  1716.  
  1717. /*
  1718.  *    Object newInstance(classOOP)
  1719.  *
  1720.  * Description
  1721.  *
  1722.  *    Creates a new instance of class "classOOP".  The space is allocated,
  1723.  *    the class and size fields of the class are filled in, and the instance
  1724.  *    is returned.  Its fields are NOT INITIALIZED.  "classOOP" must
  1725.  *    represent a class with no indexable fields.
  1726.  *
  1727.  * Inputs
  1728.  *
  1729.  *    classOOP: 
  1730.  *        OOP for the class that the new instance is to be an instance
  1731.  *        of.
  1732.  *
  1733.  * Outputs
  1734.  *
  1735.  *    The new instance, with objSize and objClass filled in.
  1736.  */
  1737. Object newInstance(classOOP)
  1738. OOP    classOOP;
  1739. {
  1740.   Object    instance;
  1741.   int        numBytes;
  1742.  
  1743.   numBytes = instanceSize(classOOP);
  1744.   instance = (Object)allocObj(numBytes);
  1745.   instance->objSize = numBytes >> 2;
  1746.   instance->objClass = classOOP;
  1747.   maybeMoveOOP(classOOP);
  1748.   return (instance);
  1749. }
  1750.  
  1751. /*
  1752.  *    int oopSizeBytes(oop)
  1753.  *
  1754.  * Description
  1755.  *
  1756.  *    Returns the size of object in bytes, exclusive of the size of the
  1757.  *    object header.
  1758.  *
  1759.  * Inputs
  1760.  *
  1761.  *    oop   : An OOP to return the size of
  1762.  *
  1763.  * Outputs
  1764.  *
  1765.  *    As in the description above.
  1766.  */
  1767. int oopSizeBytes(oop)
  1768. OOP    oop;
  1769. {
  1770.   return ((oop->object->objSize << 2) - sizeof(ObjectHeader));
  1771. }
  1772.  
  1773. int instanceSize(classOOP)
  1774. OOP    classOOP;
  1775. {
  1776.   int        numBytes;
  1777.   InstanceSpec    instanceSpec;
  1778.  
  1779.   instanceSpec = classInstanceSpec(classOOP);
  1780.   numBytes = instanceSpec.numFixedFields;
  1781.   if (instanceSpec.isPointers | instanceSpec.isWords) {
  1782.     numBytes <<= 2;
  1783.   }
  1784.  
  1785.   return (numBytes + sizeof(ObjectHeader));
  1786. }
  1787.  
  1788. Boolean isIndexable(classOOP)
  1789. OOP    classOOP;
  1790. {
  1791.   InstanceSpec    instanceSpec;
  1792.  
  1793.   instanceSpec = classInstanceSpec(classOOP);
  1794.   return (instanceSpec.isIndexable);
  1795. }
  1796.  
  1797. static InstanceSpec classInstanceSpec(classOOP)
  1798. OOP    classOOP;
  1799. {
  1800.   Class        class;
  1801.  
  1802.   class = (Class)oopToObj(classOOP);
  1803.   return (class->instanceSpec);
  1804. }
  1805.  
  1806. Boolean checkIndexableBoundsOf(oop, index)
  1807. OOP    oop;
  1808. int    index;
  1809. {
  1810.   if (isInt(oop)) {
  1811.     return (false);
  1812.   }
  1813.  
  1814.   return (index >= 1 && index <= numIndexableFields(oop));
  1815. }
  1816.  
  1817. Boolean checkBoundsOf(oop, index)
  1818. OOP    oop;
  1819. int    index;
  1820. {
  1821.   if (isInt(oop)) {
  1822.     return (false);
  1823.   }
  1824.  
  1825.   return (index >= 1 && index <= oopNumFields(oop));
  1826. }
  1827.  
  1828. Boolean classIsPointers(classOOP)
  1829. OOP    classOOP;
  1830. {
  1831.   InstanceSpec    instanceSpec;
  1832.  
  1833.   instanceSpec = classInstanceSpec(classOOP);
  1834.   return (instanceSpec.isPointers);
  1835. }
  1836.  
  1837. Boolean isPointers(oop)
  1838. OOP    oop;
  1839. {
  1840.   InstanceSpec    instanceSpec;
  1841.  
  1842.   instanceSpec = classInstanceSpec(oopClass(oop));
  1843.   return (instanceSpec.isPointers);
  1844. }
  1845.  
  1846. int oopFixedFields(oop)
  1847. OOP    oop;
  1848. {
  1849.   InstanceSpec    instanceSpec;
  1850.  
  1851.   instanceSpec = classInstanceSpec(oopClass(oop));
  1852.   if (instanceSpec.isWords) {
  1853.     return (instanceSpec.numFixedFields);
  1854.   } else {
  1855.     return (instanceSpec.numFixedFields * sizeof(OOP));
  1856.   }
  1857. }
  1858.  
  1859. static int oopNumFields(oop)
  1860. OOP    oop;
  1861. {
  1862.   Object    object;
  1863.   InstanceSpec    instanceSpec;
  1864.   int        numFields;
  1865.  
  1866.   object = oopToObj(oop);
  1867.   instanceSpec = classInstanceSpec(oopClass(oop));
  1868.  
  1869.   numFields = (object->objSize << 2) - sizeof(ObjectHeader);
  1870.   if (instanceSpec.isWords) {
  1871.     numFields >>= 2;
  1872.   } else {            /* must be bytes */
  1873.     numFields -= oop->emptyBytes;
  1874.   }
  1875.  
  1876.   return (numFields);
  1877. }
  1878.  
  1879. OOP indexOOP(oop, index)
  1880. OOP    oop;
  1881. int    index;
  1882. {
  1883.   InstanceSpec    instanceSpec;
  1884.  
  1885.   instanceSpec = classInstanceSpec(oopClass(oop));
  1886.  
  1887.   if (instanceSpec.isPointers) {
  1888.     index += instanceSpec.numFixedFields;
  1889.     return (oopToObj(oop)->data[index-1]);
  1890.   } else if (instanceSpec.isWords) {
  1891.     index += instanceSpec.numFixedFields;
  1892.     return (fromInt( ((long *)oopToObj(oop)->data)[index-1] ));
  1893.   } else {
  1894.     index += instanceSpec.numFixedFields * sizeof(OOP);
  1895.     return (fromInt( ((Byte *)oopToObj(oop)->data)[index-1] ));
  1896.   }
  1897. }
  1898.  
  1899. Boolean indexOOPPut(oop, index, value)
  1900. OOP    oop, value;
  1901. int    index;
  1902. {
  1903.   InstanceSpec    instanceSpec;
  1904.   unsigned long    valueInt;
  1905.  
  1906.   instanceSpec = classInstanceSpec(oopClass(oop));
  1907.   index += oopFixedFields(oop);
  1908.  
  1909.   if (instanceSpec.isPointers) {
  1910.     prepareToStore(oop, value);
  1911.     oopToObj(oop)->data[index-1] = value;
  1912.   } else if (instanceSpec.isWords) {
  1913.     valueInt = toInt(value);
  1914.     ((long *)oopToObj(oop)->data)[index-1] = valueInt;
  1915.   } else {
  1916.     valueInt = toInt(value);
  1917.     if (valueInt >= 256) {
  1918.       return (false);
  1919.     }
  1920.     ((Byte *)oopToObj(oop)->data)[index-1] = (Byte)valueInt;
  1921.   }
  1922.  
  1923.   return (true);
  1924. }
  1925.  
  1926. OOP indexStringOOP(oop, index)
  1927. OOP    oop;
  1928. int    index;
  1929. {
  1930.   InstanceSpec    instanceSpec;
  1931.  
  1932.   /* ??? I'm presuming that we have a string here */
  1933.  
  1934.   instanceSpec = classInstanceSpec(oopClass(oop));
  1935.   index += instanceSpec.numFixedFields;
  1936.  
  1937.   return (charOOPAt( ((Byte *)oopToObj(oop)->data)[index-1] ));
  1938. }
  1939.  
  1940. void indexStringOOPPut(oop, index, value)
  1941. OOP    oop, value;
  1942. int    index;
  1943. {
  1944.   InstanceSpec    instanceSpec;
  1945.   unsigned long    valueInt;
  1946.  
  1947.   /* ??? I'm presuming that we have a string oop here */
  1948.  
  1949.   instanceSpec = classInstanceSpec(oopClass(oop));
  1950.   index += instanceSpec.numFixedFields;
  1951.  
  1952.   ((Byte *)oopToObj(oop)->data)[index-1] = charOOPValue(value);
  1953. }
  1954.  
  1955. OOP stringNew(s)
  1956. char    *s;
  1957. {
  1958.   String    string;
  1959.   int        len;
  1960.   OOP        stringOOP;
  1961.  
  1962.   len = strlen(s);
  1963.   string = (String)newInstanceWith(stringClass, len);
  1964.   strncpy(string->chars, s, len);
  1965.  
  1966.   stringOOP = allocOOP(string);
  1967.   stringOOP->emptyBytes = (4 - len) & 3;
  1968.  
  1969.   return (stringOOP);
  1970. }
  1971.  
  1972. void setOOPString(stringOOP, s)
  1973. OOP    stringOOP;
  1974. char    *s;
  1975. {
  1976.   String    string;
  1977.   long        len;
  1978.  
  1979.   len = strlen(s);
  1980.   string = (String)newInstanceWith(stringClass, len);
  1981.   strncpy(string->chars, s, len);
  1982.  
  1983.   setOOPObject(stringOOP, string);
  1984.   stringOOP->emptyBytes = (4 - len) & 3;
  1985. }
  1986.  
  1987. Byte *stringOOPChars(stringOOP)
  1988. OOP    stringOOP;
  1989. {
  1990.   String    string;
  1991.  
  1992.   string = (String)oopToObj(stringOOP);
  1993.   return ((Byte *)string->chars);
  1994. }
  1995.  
  1996. Byte *toCString(stringOOP)
  1997. OOP    stringOOP;
  1998. {
  1999.   Byte        *result, *chars;
  2000.   int        len;
  2001.   String    string;
  2002.  
  2003.   string = (String)oopToObj(stringOOP);
  2004.   len = oopNumFields(stringOOP);
  2005.   result = (Byte *)malloc(len + 1);
  2006.   strncpy(result, string->chars, len);
  2007.   result[len] = '\0';
  2008.  
  2009.   return (result);
  2010. }
  2011.  
  2012. Byte *toByteArray(byteArrayOOP)
  2013. OOP    byteArrayOOP;
  2014. {
  2015.   Byte        *result;
  2016.   int        len;
  2017.   ByteArray    byteArray;
  2018.  
  2019.   byteArray = (ByteArray)oopToObj(byteArrayOOP);
  2020.   len = oopNumFields(byteArrayOOP);
  2021.   result = (Byte *)malloc(len);
  2022.   memcpy(result, byteArray->bytes, len);
  2023.  
  2024.   return (result);
  2025. }
  2026.  
  2027. OOP instVarAt(oop, index)
  2028. OOP    oop;
  2029. int    index;
  2030. {
  2031.   InstanceSpec    instanceSpec;
  2032.  
  2033.   instanceSpec = classInstanceSpec(oopClass(oop));
  2034.  
  2035.   if (instanceSpec.isPointers) {
  2036.     return (oopToObj(oop)->data[index-1]);
  2037.   } else if (instanceSpec.isWords) {
  2038.     return (fromInt( ((long *)oopToObj(oop)->data)[index-1] ));
  2039.   } else {
  2040.     return (fromInt( ((Byte *)oopToObj(oop)->data)[index-1] ));
  2041.   }
  2042. }
  2043.  
  2044. Boolean instVarAtPut(oop, index, value)
  2045. OOP    oop, value;
  2046. int    index;
  2047. {
  2048.   InstanceSpec    instanceSpec;
  2049.   unsigned long    valueInt;
  2050.  
  2051.   instanceSpec = classInstanceSpec(oopClass(oop));
  2052.  
  2053.   if (instanceSpec.isPointers) {
  2054.     if (GCIsOn()) {
  2055.       prepareToStore(oop, value);
  2056.     }
  2057.     oopToObj(oop)->data[index-1] = value;
  2058.   } else if (instanceSpec.isWords) {
  2059.     valueInt = toInt(value);
  2060.     ((long *)oopToObj(oop)->data)[index-1] = valueInt;
  2061.   } else {
  2062.     valueInt = toInt(value);
  2063.     if (valueInt >= 256) {
  2064.       return (false);
  2065.     }
  2066.     ((Byte *)oopToObj(oop)->data)[index-1] = (Byte)valueInt;
  2067.   }
  2068.  
  2069.   return (true);
  2070. }
  2071.  
  2072. int numIndexableFields(oop)
  2073. OOP    oop;
  2074. {
  2075.   if (isInt(oop)) {
  2076.     return (0);
  2077.   }
  2078.  
  2079.   return (oopNumFields(oop) - oopFixedFields(oop));
  2080. }
  2081.  
  2082. OOP arrayNew(numElts)
  2083. int    numElts;
  2084. {
  2085.   return (allocOOP(instantiateWith(arrayClass, numElts)));
  2086. }
  2087.  
  2088. OOP arrayAt(arrayOOP, index)
  2089. OOP    arrayOOP;
  2090. int    index;
  2091. {
  2092.   return ( ((Array)oopToObj(arrayOOP))->elements[index-1]);
  2093. }
  2094.  
  2095. void arrayAtPut(arrayOOP, index, value)
  2096. OOP    arrayOOP, value;
  2097. int    index;
  2098. {
  2099.   prepareToStore(arrayOOP, value);
  2100.   ((Array)oopToObj(arrayOOP))->elements[index-1] = value;
  2101. }
  2102.  
  2103. OOP floatNew(f)
  2104. double    f;
  2105. {
  2106.   FloatObject    floatObject;
  2107.  
  2108.   /*
  2109.    * ### Seems like this can lose on architectures where floats need
  2110.    * to be aligned...there are no guarantees that the float data
  2111.    * is aligned to an 8 byte boundary, so the store could lose.
  2112.    */
  2113.   floatObject = (FloatObject)newInstanceWith(floatClass, 2);
  2114.   floatObject->value = f;
  2115.   
  2116.   return (allocOOP(floatObject));
  2117. }
  2118.  
  2119. double floatOOPValue(floatOOP)
  2120. OOP    floatOOP;
  2121. {
  2122.   Object obj;
  2123.   union {
  2124.     long l[2];
  2125.     double d;
  2126.   } hack;
  2127.  
  2128.   if (DOUBLE_ALIGNMENT > sizeof(long)) {
  2129.     /* we may not be aligned properly...fetch things out the hard way */
  2130.     obj = oopToObj(floatOOP);
  2131.     hack.l[0] = (long)obj->data[0];
  2132.     hack.l[1] = (long)obj->data[1];
  2133.     return (hack.d);
  2134.   } else {
  2135.     return (((FloatObject)oopToObj(floatOOP))->value);
  2136.   }
  2137. }
  2138.  
  2139. OOP messageNewArgs(selectorOOP, argsArray)
  2140. OOP    selectorOOP, argsArray;
  2141. {
  2142.   Message    message;
  2143.  
  2144.   message = (Message)newInstance(messageClass);
  2145.   maybeMoveOOP(selectorOOP);
  2146.   message->selector = selectorOOP;
  2147.   maybeMoveOOP(argsArray);
  2148.   message->args = argsArray;
  2149.  
  2150.   return (allocOOP(message));
  2151. }
  2152.  
  2153. OOP messageSelector(messageOOP)
  2154. OOP    messageOOP;
  2155. {
  2156.   Message    message;
  2157.  
  2158.   message = (Message)oopToObj(messageOOP);
  2159.   return (message->selector);
  2160. }
  2161.  
  2162. OOP messageArgs(messageOOP)
  2163. OOP    messageOOP;
  2164. {
  2165.   Message    message;
  2166.  
  2167.   message = (Message)oopToObj(messageOOP);
  2168.   return (message->args);
  2169. }
  2170.  
  2171.  
  2172. OOP cObjectNew(cObjPtr)
  2173. voidPtr    *cObjPtr;
  2174. {
  2175.   Object    cObject;
  2176.  
  2177.   cObject = (Object)newInstanceWith(cObjectClass, 1);
  2178.   cObject->data[0] = (OOP)cObjPtr;
  2179.   
  2180.   return (allocOOP(cObject));
  2181. }
  2182.  
  2183. voidPtr cObjectValue(cObjOOP)
  2184. OOP    cObjOOP;
  2185. {
  2186.   Object    cObject;
  2187.  
  2188.   cObject = oopToObj(cObjOOP);
  2189.   return ((voidPtr)cObject->data[0]);
  2190. }
  2191.  
  2192. void setCObjectValue(cObjOOP, value)
  2193. OOP    cObjOOP;
  2194. voidPtr    value;
  2195. {
  2196.   Object    cObject;
  2197.  
  2198.   cObject = oopToObj(cObjOOP);
  2199.   cObject->data[0] = (OOP)value;
  2200. }
  2201.